package com.maxd.controller.alipay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayFundTransToaccountTransferRequest;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayFundTransToaccountTransferResponse;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.maxd.adapter.IgnoreSecurity;
import com.maxd.constants.AliPayConstants;
import com.maxd.constants.AliPayNotifyParamConstants;
import com.maxd.error.Result;
import com.maxd.error.ResultUtil;
import com.maxd.model.*;
import com.maxd.respository.common.CommonRepository;
import com.maxd.respository.pay.PayDetailsJpaRepository;
import com.maxd.respository.pay.PayDetailsRepository;
import com.maxd.service.userMoney.UserMoneyDetailsService;
import com.maxd.service.userMoney.UserMoneyService;
import com.maxd.utils.AliPayOrderUtil;
import com.maxd.utils.AmountCalUtils;
import com.maxd.utils.Config;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 支付宝支付处理--暂不做同步处理、回调方式使用异步
 */
@Api(value="支付宝管理",tags={"支付宝管理"})
@Slf4j
@RestController
@RequestMapping("/api/aliPay")
public class AliPayController {

    @Autowired
    private PayDetailsJpaRepository payDetailsJpaRepository;
    @Autowired
    private PayDetailsRepository payDetailsRepository;
    @Autowired
    private UserMoneyService userMoneyService;
    @Autowired
    private UserMoneyDetailsService userMoneyDetailsService;
    @Autowired
    private CommonRepository commonRepository;
    private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 创建线程池处理业务逻辑
     */
    private ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().build();
    private ExecutorService singleThreadPool = new ThreadPoolExecutor(30, 100,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());

    /**
     * 支付宝网页支付
     *
     * @param response
     * @throws IOException
     */
    @RequestMapping("/payment")
    public void aliPay(HttpServletResponse response) throws IOException {

        AlipayClient alipayClient = new DefaultAlipayClient(AliPayConstants.REQUEST_URL,
                commonRepository.findOne(63).getValue(), commonRepository.findOne(65).getValue(), AliPayConstants.FORMAT,
                AliPayConstants.CHARSET, commonRepository.findOne(64).getValue(), AliPayConstants.SIGNTYPE);
        //封装请求参数
        AlipayTradeWapPayRequest aliPayRequest = new AlipayTradeWapPayRequest();
        AliPayParamModel aliPayParamModel = new AliPayParamModel();
        aliPayParamModel.setOut_trade_no("2018120514559696060");
        aliPayParamModel.setSubject("支付测试");
        aliPayParamModel.setTotal_amount("0.01");
        aliPayParamModel.setProduct_code(AliPayConstants.PRODUCT_CODE);
        // TODO 同步处理业务-涉及到商户自定义页面跳转
        aliPayRequest.setReturnUrl("http://ip:port/api/aliPay/return");
        // TODO 异步处理业务-修改订单状态、校验签名是否正确
        aliPayRequest.setNotifyUrl("http://ip:port/api/aliPay/notify");
        aliPayRequest.setBizContent(JSON.toJSONString(aliPayParamModel));
        try {
            // 调用SDK生成表单
            String form = alipayClient.pageExecute(aliPayRequest).getBody();
            response.setContentType("text/html;charset=" + AliPayConstants.CHARSET);
            response.getWriter().write(form);
            response.getWriter().flush();
            response.getWriter().close();
        } catch (AlipayApiException e) {
            log.info("支付宝支付异常，异常信息为:" + e.getErrMsg());
            e.printStackTrace();
        }
    }

//    /**
//     * 支付宝提现
//     */
//    @RequestMapping("/withdraw")
//    public void withdraw() {
//        val aliPayWithdrawModel = AliPayWithdrawModel.builder()
//                .out_biz_no("20181206145569697")
//                .amount(new BigDecimal(0.2))
//                .payee_account("支付宝账号")
//                .payee_real_name("真实姓名")
//                .payee_type(AliPayConstants.PAY_TYPE)
//                .remark("测试支付宝提现")
//                .build();
//        String json = JSON.toJSONString(aliPayWithdrawModel);
//        //实例化连接对象
//        AlipayFundTransToaccountTransferRequest withdrawRequest = new AlipayFundTransToaccountTransferRequest();
//        withdrawRequest.setBizContent(json);
//        try {
//            AlipayFundTransToaccountTransferResponse response = alipayClient.execute(withdrawRequest);
//            if (AliPayConstants.SUCCESS_CODE.equalsIgnoreCase(response.getCode())) {
//                // TODO 处理业务逻辑
//            }
//        } catch (AlipayApiException e) {
//            log.info("零钱提现异常原因:" + e.getMessage());
//            e.printStackTrace();
//        }
//    }

    /**
     * 支付宝异步通知地址
     *
     * @param request
     * @return
     */
    @ApiOperation("支付宝回调地址")
    @RequestMapping("/notify")
    @Transactional(rollbackFor = Exception.class)
    @IgnoreSecurity
    public void returnUrl(HttpServletRequest request, HttpServletResponse response) {
        Map<String, String> params = AliPayOrderUtil.convertRequestParamsToMap(request);
        String result = "";
        //调用SDK验证签名
        boolean signVerified = false;
        try {
            signVerified = AlipaySignature.rsaCheckV1(params, commonRepository.findOne(64).getValue(),
                    AliPayConstants.CHARSET, AliPayConstants.SIGNTYPE);
        } catch (AlipayApiException e) {
            log.info("支付宝回调验签异常：" + e.getMessage());
            e.printStackTrace();
        }
        if (signVerified) {
            this.check(params);
            singleThreadPool.execute(() -> {
                AliPayNotifyParamConstants param = AliPayOrderUtil.buildAliPayNotifyParam(params);
            });
            result = "success";
        } else {
            result = "failure";
        }
        try {
            BufferedOutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
            outputStream.write(result.getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            log.info("支付宝返回异常，异常信息为：" + e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 校验支付宝支付返回的订单信息是否正确
     *
     * @param params
     */
    private void check(Map<String, String> params) {
        for (String key : params.keySet()){
            log.info("key="+key+";  value="+params.get(key));
        }
            // TODO 判断支付订单号是否是同一个
        String outTradeNo = params.get("out_trade_no");
        // 订单支付金额是否正确
        BigDecimal totalAmount = new BigDecimal(params.get("total_amount"));
//        Assert.isTrue(!totalAmount.equals(new BigDecimal(0.2)), "支付金额错误");
        // 判断支付的商户信息是否一致
        Assert.isTrue(params.get("app_id").equals(commonRepository.findOne(63).getValue()), "支付的商户信息不正确");
    }

    @ApiOperation("支付宝回调")
    @RequestMapping("/notifyApp")
    @Transactional(rollbackFor = Exception.class)
    @IgnoreSecurity
    public void notifyApp(HttpServletRequest request, HttpServletResponse response){
        //获取支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<String,String>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用。
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }
        //切记alipaypublickey是支付宝的公钥，请去open.alipay.com对应应用下查看。
        //boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
        try {
            log.info("回调成功！！！");
            boolean flag = AlipaySignature.rsaCheckV1(params, commonRepository.findOne(64).getValue(), AliPayConstants.CHARSET,"RSA2");
            log.info(flag+"回调验证信息");
            if(flag){
                String tradeStatus = params.get("trade_status");
                if("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)){
                    String outTradeNo = params.get("out_trade_no");
                    PayDetails payDetails=payDetailsRepository.selectByOrderId(outTradeNo);
                    if(payDetails.getState()==0){
                        payDetailsRepository.updateState(payDetails.getId(),1,new Date());
                        userMoneyService.updateMoney(1,payDetails.getUserId(),payDetails.getMoney());
                        UserMoneyDetails userMoneyDetails=new UserMoneyDetails();
                        userMoneyDetails.setUserId(payDetails.getUserId());
                        userMoneyDetails.setTitle("充值："+payDetails.getMoney());
                        userMoneyDetails.setContent("支付宝充值金额："+payDetails.getMoney());
                        userMoneyDetails.setType(1);
                        userMoneyDetails.setMoney(payDetails.getMoney());
                        userMoneyDetails.setCreateTime(sdf.format(new Date()));
                        userMoneyDetailsService.save(userMoneyDetails);
                    }
                }

            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.info("回调验证失败！！！");
        }
    }



    @ApiOperation("app支付")
    @RequestMapping("/payApp")
    @Transactional(rollbackFor = Exception.class)
    public Result payApp(Long userId,String money){
        log.info("开始下单了！！");
        CommonInfo one = commonRepository.findOne(19);
        String url=one.getValue()+"/tao/api/aliPay/notifyApp";
        log.info("回调地址:"+url);
        String outTradeNo=getGeneralOrder();
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", commonRepository.findOne(63).getValue(), commonRepository.findOne(65).getValue(), "json", AliPayConstants.CHARSET, commonRepository.findOne(64).getValue(), "RSA2");
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(Config.BASE_NAME);
        model.setSubject(Config.BASE_NAME);
        model.setOutTradeNo(outTradeNo);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(money+".00");
//        model.setTotalAmount("0.01");
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl(url);
        try {

            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            if(response.isSuccess()){
            SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            //创建订单信息
            PayDetails payDetails=new PayDetails();
            payDetails.setState(0);
            payDetails.setCreateTime(sdf.format(new Date()));
            payDetails.setOrderId(outTradeNo);
            payDetails.setUserId(userId);
            payDetails.setMoney(Double.parseDouble(money));
            payDetails.setClassify(2);
            payDetailsJpaRepository.save(payDetails);
            return ResultUtil.success(response.getBody());
            } else {
                log.info("调用失败");
                ResultUtil.error(-100,"获取订单失败！");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return ResultUtil.error(-100,"获取订单失败！");

    }

    @ApiOperation("h5支付")
    @RequestMapping(value = "/payH5",method = RequestMethod.POST)
    @Transactional(rollbackFor = Exception.class)
    public Result payH5( Long userId,String money) {
        CommonInfo urls = commonRepository.findOne(19);
        String url=urls.getValue()+"/tao/api/aliPay/notifyApp";
        log.info("回调地址:"+url);
        String outTradeNo=getGeneralOrder();
        try {
            CommonInfo one1 = commonRepository.findOne(12);
            String name=one1==null?"助力任务":one1.getValue();
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", commonRepository.findOne(63).getValue(), commonRepository.findOne(65).getValue(), "json", AliPayConstants.CHARSET, commonRepository.findOne(64).getValue(), "RSA2");
            AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
            JSONObject order = new JSONObject();
            order.put("out_trade_no",outTradeNo); //订单号
            order.put("subject", name); //商品标题
            order.put("product_code", "QUICK_WAP_WAY");
            order.put("body", name);//商品名称
            order.put("total_amount", money+".00"); //金额
            alipayRequest.setBizContent(order.toString());
            //在公共参数中设置回跳和通知地址
            alipayRequest.setNotifyUrl(url);
            //通知页面地址
            CommonInfo one = commonRepository.findOne(19);
            if(one!=null){
                alipayRequest.setReturnUrl(one.getValue()+"/#/pages/task/recharge");
            }else{
                alipayRequest.setReturnUrl("http://renwu.xiansqx.com/#/pages/task/recharge");
            }
            String form = alipayClient.pageExecute(alipayRequest).getBody();
            /*response.setContentType("text/html;charset=utf-8");
            response.getWriter().write(form);
            response.getWriter().flush();
            response.getWriter().close();*/
            //创建订单信息
            PayDetails payDetails=new PayDetails();
            payDetails.setState(0);
            payDetails.setCreateTime(sdf.format(new Date()));
            payDetails.setOrderId(outTradeNo);
            payDetails.setUserId(userId);
            payDetails.setMoney(Double.parseDouble(money));
            payDetails.setClassify(2);
            payDetailsJpaRepository.save(payDetails);
            return ResultUtil.success(form);
        } catch (AlipayApiException e) {
            log.error("CreatPayOrderForH5", e);
        }
        return ResultUtil.error(-100,"获取订单信息错误！");
    }



    /*@RequestMapping("/payApp")
    @Transactional(rollbackFor = Exception.class)
    public Result payApp(Long userId,String money){
        AlipayClient alipayClient = new DefaultAlipayClient(AliPayConstants.REQUEST_URL,AliPayConstants.OPEN_ID,AliPayConstants.BUS_RAS_PRIVATE_KET,AliPayConstants.FORMAT,AliPayConstants.CHARSET,AliPayConstants.RAS_PUBLIC_KEY,AliPayConstants.SIGNTYPE);
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        String url=profileHttpUrl+"/api/aliPay/notify";
        String outTradeNo=getGeneralOrder();
        request.setBizContent("{" +
                "\"timeout_express\":\"90m\"," +
                "\"total_amount\":\""+money+".00\"," +
                "\"body\":\""+Config.BASE_NAME+"\"," +
                "\"subject\":\""+Config.BASE_NAME+"\"," +
                "\"out_trade_no\":\""+outTradeNo+"\"," +
                "\"sign_notify_url\":\""+url+"\"" +
                "  }");
        AlipayTradeAppPayResponse response = null;
        try {
            response = alipayClient.sdkExecute(request);
            if(response.isSuccess()){
                SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                //创建订单信息
                PayDetails payDetails=new PayDetails();
                payDetails.setState(0);
                payDetails.setCreateTime(sdf.format(new Date()));
                payDetails.setOrderId(outTradeNo);
                payDetails.setUserId(userId);
                payDetails.setMoney(Double.parseDouble(money));
                payDetails.setClassify(2);
                payDetailsJpaRepository.save(payDetails);
                return ResultUtil.success(response.getBody());
            } else {
                log.info("调用失败");
                ResultUtil.error(-100,"获取订单失败！");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return ResultUtil.error(-100,"获取订单失败！");
    }*/


    public String getGeneralOrder(){
        Date date=new Date();
        String newString = String.format("%0"+4+"d", (int)((Math.random()*9+1)*1000));
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String format = sdf.format(date);
        return format+newString;
    }

}
